﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GameNode
{
    class NodeGameLogic
    {
        private readonly GameField gameField;
        private readonly Drawer drawer;
        private readonly Random rnd;
        private List<ConsoleNode> nodes;
        private ConsoleNode target;

        private int nodeCount;
        private readonly InputHandler _ih;
        public Direction _dir = Direction.Up;
        public bool isGameOver = false;
        public int RoundCounter = 1;
        public int TailCount = 0;


        public NodeGameLogic(GameField gameField, Drawer drawer, int nodeCount, InputHandler ih)
        {
            this.gameField = gameField;
            this.drawer = drawer;
            this.nodeCount = nodeCount;

            _ih = ih;
            _ih.KeyLeft += MoveNodeLeft;
            _ih.KeyRight += MoveNodeRight;
            _ih.KeyUp += MoveNodeUp;
            _ih.KeyDown += MoveNodeDown;


            rnd = new Random();
            nodes = new List<ConsoleNode>();
            target = GenerateRandomTarget((char)1, ConsoleColor.White);

        }


        public void StartGame()
        {

            for (int z = 0; z < 1000; z++)
            {
                nodes = new List<ConsoleNode>()
                {
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),((gameField.Y+(gameField.Y+gameField.Height))/2),'@', ConsoleColor.Green),
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),(((gameField.Y+(gameField.Y+gameField.Height))/2)+1),'O', ConsoleColor.Green),
                    new ConsoleNode(((gameField.X+(gameField.X+gameField.Width))/2),(((gameField.Y+(gameField.Y+gameField.Height))/2)+2),'F', ConsoleColor.Green),
                };

                GameOver();
                drawer.DrawListAndScore(nodes, gameField, 5, RoundCounter, TailCount);
                do
                {

                    drawer.DrawListAndScore(nodes, gameField, 5, RoundCounter, TailCount);
                    drawer.DrawGameField(gameField, '0');
                    drawer.DrawNodeList(nodes);

                    drawer.DrawNode(target);
                    _ih.QueryKB();

                    for (int i = nodes.Count - 1; i > 0; i--)
                    {
                        nodes[i].X = nodes[i - 1].X;
                        nodes[i].Y = nodes[i - 1].Y;
                    }

                    SnakeStyleMoving(nodes[0], _dir, CheckPosition);


                    for (int i = 0; i < nodes.Count; i++)
                    {
                        if (IsNodeOnTarget(nodes[i]))
                        {

                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, 'O', ConsoleColor.Green));
                            TailCount++;
                            if (TailCount % 10 == 0)
                            {
                                RoundCounter++;
                            }
                            target = GenerateRandomTarget((char)1, ConsoleColor.White);
                        }
                    }
                    Thread.Sleep(120 - (RoundCounter * 4));
                }
                while (!isGameOver);
               
            }
            
            Console.ReadKey();
        }

        private ConsoleNode GenerateRandomTarget(char symbol, ConsoleColor color)
        {

            int randomX = 0;
            int randomY = 0;
            do
            {
                randomX = rnd.Next(gameField.X, gameField.Width + gameField.X);
                randomY = rnd.Next(gameField.Y, gameField.Height + gameField.Y);

            } while (!IsPositionFree(randomX, randomY));

            return new ConsoleNode(randomX, randomY, symbol, color);
        }

        private bool IsPositionFree(int x, int y)
        {
            foreach (var nd in nodes)
            {
                if (nd.IsOnPossition(x, y))
                    return false;
            }
            return true;
        }

        private bool IsNodeOnTarget(ConsoleNode node)
        {
            if (node.X == target.X && node.Y == target.Y)
                return true;
            return false;
        }

        private Position CheckPosition(int x, int y)
        {
            if (!IsPositionFree(x, y))
                return Position.Node;
            if (!gameField.IsOnField(x, y))
                return Position.Border;
            return Position.Free;
        }

        private void MoveNodeLeft(object sender, EventArgs e)
        {
            if (_dir != Direction.Right)
                _dir = Direction.Left;
        }

        private void MoveNodeRight(object sender, EventArgs e)
        {
            if (_dir != Direction.Left)
                _dir = Direction.Right;
        }


        private void MoveNodeUp(object sender, EventArgs e)
        {
            if (_dir != Direction.Down)
                _dir = Direction.Up;
        }

        private void MoveNodeDown(object sender, EventArgs e)
        {
            if (_dir != Direction.Up)
                _dir = Direction.Down;
        }

        public void TailMovement(List<ConsoleNode> nodeList)
        {
            //node.X = nodeList[nodeList.IndexOf(node) - 1].X;
            //node.Y = nodeList[nodeList.IndexOf(node) - 1].Y;
        }

        public void SnakeStyleMoving(ConsoleNode node, Direction _dir, Func<int, int, Position> positionStatus)
        {
            if (_dir == Direction.Up)
            {
                if (positionStatus(node.X, node.Y - 1) == Position.Free)
                    node.MoveUp();
                else if ((positionStatus(node.X, node.Y - 1) == Position.Border) || (positionStatus(node.X, node.Y - 1) == Position.Node))
                    isGameOver = true;
            }
            if (_dir == Direction.Left)
            {
                if (positionStatus(node.X - 1, node.Y) == Position.Free)
                    node.MoveLeft();
                else if ((positionStatus(node.X - 1, node.Y) == Position.Border) || (positionStatus(node.X - 1, node.Y) == Position.Node))
                    isGameOver = true;
            }
            if (_dir == Direction.Right)
            {
                if (positionStatus(node.X + 1, node.Y) == Position.Free)
                    node.MoveRight();
                else if ((positionStatus(node.X+1, node.Y) == Position.Border) || (positionStatus(node.X+1, node.Y) == Position.Node))
                    isGameOver = true;
            }
            if (_dir == Direction.Down)
            {
                if (positionStatus(node.X, node.Y + 1) == Position.Free)
                    node.MoveDown();
                else if ((positionStatus(node.X, node.Y + 1) == Position.Border) || (positionStatus(node.X, node.Y + 1) == Position.Node))
                    isGameOver = true;
            }
        }

        public void GameOver()
        {
            if (isGameOver == true)
            {
                drawer.GameOverMessage(nodes,gameField);
                isGameOver = false;
                TailCount = 0;
                RoundCounter = 1;
                _dir = Direction.Up;
              
                StartGame();
            }

        }


    }

    public enum Position
    {
        Node,
        Border,
        Free
    }

    public enum Direction
    {
        Up,
        Down,
        Right,
        Left
    }
}